package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.lang.Assert;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private VodService vodService;

    /**
     * 保存声音
     *
     * @param userId    用户ID
     * @param trackInfo 专辑信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(Long userId, TrackInfo trackInfo) {
        //1.根据专辑ID查询专辑信息-更新专辑信息；复用专辑封面图片
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());

        //2.新增声音
        //2.1 设置声音额外基本信息：用户ID，声音排序序号，状态，来源
        trackInfo.setUserId(userId);
        trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
        trackInfo.setSource(SystemConstant.TRACK_SOURCE_USER);
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);
        if (StringUtils.isBlank(trackInfo.getCoverUrl())) {
            trackInfo.setCoverUrl(albumInfo.getCoverUrl());
        }
        //2.2 远程调用腾讯点播平台获取音频详情信息
        TrackMediaInfoVo mediaInfoVo = vodService.getMediaInfo(trackInfo.getMediaFileId());
        if (mediaInfoVo != null) {
            trackInfo.setMediaDuration(BigDecimal.valueOf(mediaInfoVo.getDuration()));
            trackInfo.setMediaSize(mediaInfoVo.getSize());
            trackInfo.setMediaType(mediaInfoVo.getType());
        }
        //2.3 新增声音
        trackInfoMapper.insert(trackInfo);
        Long trackId = trackInfo.getId();


        //3.更新专辑信息（包含声音数量）
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        albumInfoMapper.updateById(albumInfo);

        //4.初始化声音统计信息
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PLAY, 0);
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COLLECT, 0);
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PRAISE, 0);
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COMMENT, 0);

        String suggestTitle = vodService.scanText(trackInfo.getTrackTitle());
        String suggestIntro = vodService.scanText(trackInfo.getTrackIntro());
        if (!"pass".equals(suggestTitle) || !"pass".equals(suggestIntro)) {
            throw new GuiguException(500, "声音标题或简介内容存在违规！");
        }

        //5.TODO 调用点播平台发起音频文件审核任务（异步审核）
        String reviewTaskId = vodService.reviewTask(trackInfo.getMediaFileId());
        trackInfo.setReviewTaskId(reviewTaskId);
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEWING);
        trackInfoMapper.updateById(trackInfo);
    }

    @Autowired
    private TrackStatMapper trackStatMapper;

    /**
     * 保存声音统计信息
     *
     * @param trackId  声音ID
     * @param statType 统计类型
     * @param statNum  统计数值
     */
    @Override
    public void saveTrackStat(Long trackId, String statType, int statNum) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statType);
        trackStat.setStatNum(statNum);
        trackStatMapper.insert(trackStat);
    }

    /**
     * 条件分页查询当前用户声音列表（包含声音统计信息）
     *
     * @param pageInfo       分页对象
     * @param trackInfoQuery 查询条件（用户ID，关键字，审核状态）
     * @return
     */
    @Override
    public Page<TrackListVo> getUserTrackPage(Page<TrackListVo> pageInfo, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.getUserTrackPage(pageInfo, trackInfoQuery);
    }

    /**
     * 更新声音信息
     *
     * @param trackInfo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTrackInfo(TrackInfo trackInfo) {
        //1.判断音频文件是否变更（如果变更，获取最新音频详情，删除原来音频文件）
        TrackInfo trackInfoDB = trackInfoMapper.selectById(trackInfo.getId());
        //2.执行声音记录修改
        String mediaFileIdOld = trackInfoDB.getMediaFileId();
        String mediaFileIdNew = trackInfo.getMediaFileId();
        if (!mediaFileIdOld.equals(mediaFileIdNew)) {
            //2.1 再次获取变更后音频文件详情
            TrackMediaInfoVo mediaInfo = vodService.getMediaInfo(mediaFileIdNew);
            if (mediaInfo != null) {
                trackInfo.setMediaSize(mediaInfo.getSize());
                trackInfo.setMediaType(mediaInfo.getType());
                trackInfo.setMediaDuration(BigDecimal.valueOf(mediaInfo.getDuration()));
                //2.2 从点播平台删除旧的音频文件
                vodService.deleteMedia(mediaFileIdOld);
            }
        }
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);
        trackInfoMapper.updateById(trackInfo);

        //3.TODO 对内容（文本，音频）进行再次审核
        String suggestTitle = vodService.scanText(trackInfo.getTrackTitle());
        String suggestIntro = vodService.scanText(trackInfo.getTrackIntro());
        if (!"pass".equals(suggestTitle) || !"pass".equals(suggestIntro)) {
            throw new GuiguException(500, "声音标题或简介内容存在违规！");
        }
        String reviewTaskId = vodService.reviewTask(mediaFileIdNew);
        trackInfo.setReviewTaskId(reviewTaskId);
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEWING);
        trackInfoMapper.updateById(trackInfo);
    }

    /**
     * 删除声音记录
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long id) {
        //1.根据ID查询欲被删除声音记录-得到专辑ID跟声音序号
        TrackInfo deleteTrackInfo = trackInfoMapper.selectById(id);
        Long albumId = deleteTrackInfo.getAlbumId();
        Integer orderNum = deleteTrackInfo.getOrderNum();

        //2.更新声音表序号-确保连续
        LambdaUpdateWrapper<TrackInfo> updateWrapper = new LambdaUpdateWrapper<>();
        //2.1 更新条件
        updateWrapper.eq(TrackInfo::getAlbumId, albumId);
        updateWrapper.gt(TrackInfo::getOrderNum, orderNum);
        //2.2 修改字段值
        updateWrapper.setSql("order_num = order_num - 1");
        trackInfoMapper.update(null, updateWrapper);

        //3.删除声音表记录
        trackInfoMapper.deleteById(id);

        //4.删除声音统计
        LambdaQueryWrapper<TrackStat> trackStatLambdaQueryWrapper = new LambdaQueryWrapper<>();
        trackStatLambdaQueryWrapper.eq(TrackStat::getTrackId, id);
        trackStatMapper.delete(trackStatLambdaQueryWrapper);

        //5.更新专辑包含声音数量
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);

        //6.删除点播平台音频文件
        vodService.deleteMedia(deleteTrackInfo.getMediaFileId());
    }

    @Autowired
    private UserFeignClient userFeignClient;

    /**
     * 分页查询当前用户可见声音列表-动态判断声音付费标识
     *
     * @param pageInfo 分页对象
     * @param albumId  专辑ID
     * @param userId   用户ID
     * @return
     */
    @Override
    public Page<AlbumTrackListVo> getAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, Long albumId, Long userId) {
        //1.分页查询专辑下声音列表 TODO 暂不考虑声音付费标识 默认Vo对象AlbumTrackListVo付费标识：false
        pageInfo = trackInfoMapper.getAlbumTrackPage(pageInfo, albumId);

        //2.根据专辑ID查询专辑信息.得到付费类型，试听集数
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //2.1 付费类型: 0101-免费、0102-vip免费、0103-付费
        String payType = albumInfo.getPayType();
        //2.2 获取当前专辑免费试听集数
        Integer tracksForFree = albumInfo.getTracksForFree();

        //3.判断用户未登录情况
        if (userId == null) {
            //3.1 专辑付费类型：VIP免费或付费
            if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType) || SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
                //3.2 除去试听其他声音将付费标识全部设置true
                pageInfo.getRecords()
                        .stream()
                        .filter(vo -> vo.getOrderNum() > tracksForFree)
                        .forEach(vo -> vo.setIsShowPaidMark(true));
            }
        } else {
            //4.判断用户已登录情况
            //4.1 远程调用用户服务获取用户信息：是否VIP用户
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
            Assert.notNull(userInfoVo, "用户：{}不存在！", userId);
            Boolean isVIP = false;
            if (1 == userInfoVo.getIsVip().intValue() && userInfoVo.getVipExpireTime().after(new Date())) {
                //会员标识必须是1，且会员过期时间大于当前系统时间
                isVIP = true;
            }
            Boolean isNeedCheck = false;
            //4.2 判断专辑付费类型=VIP免费 当前用户是普通用户,都需要进一步判断声音购买情况
            if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType) && !isVIP) {
                isNeedCheck = true;
            }
            //4.3 判断专辑付费类型=付费 所有用户都需要进一步判断声音购买情况
            if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
                isNeedCheck = true;
            }
            //4.4 远程调用用户服务获取本页中所有声音购买情况
            if (isNeedCheck) {
                //4.4.1 获取本页中需要检查购买情况声音（去掉免费试听）
                List<Long> needCheckBuyStateTrackIds =
                        pageInfo.getRecords()
                                .stream()
                                .filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
                                .map(AlbumTrackListVo::getTrackId)
                                .collect(Collectors.toList());
                //4.4.1 根据用户ID+专辑ID+本页中声音ID列表，远程调用用户服务检查声音购买情况
                Map<Long, Integer> buyStateMap = userFeignClient.userIsPaidTrack(userId, albumId, needCheckBuyStateTrackIds).getData();

                //4.5 根据本页中购买情况：如果声音购买状态为未购买（0）将付费标识改为：true
                pageInfo.getRecords()
                        .stream()
                        .filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
                        .forEach(albumTrackListVo -> {
                            //如果声音ID未购买，将付费标识设置true
                            if (buyStateMap.get(albumTrackListVo.getTrackId()).intValue() == 0) {
                                albumTrackListVo.setIsShowPaidMark(true);
                            }
                        });
            }
        }
        return pageInfo;
    }

    @Autowired
    private AlbumStatMapper albumStatMapper;

    /**
     * 更新声音统计数值
     * 注意：如果声音被播放，被评论 所属专辑也需要更新统计数值
     *
     * @param mqVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStat(TrackStatMqVo mqVo) {
        //1.更新声音统计数值
        LambdaUpdateWrapper<TrackStat> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(TrackStat::getTrackId, mqVo.getTrackId());
        updateWrapper.eq(TrackStat::getStatType, mqVo.getStatType());
        updateWrapper.setSql("stat_num=stat_num+" + mqVo.getCount());
        trackStatMapper.update(null, updateWrapper);
        //2.如果统计类型是：声音播放 所属专辑统计信息也一并修改
        if (SystemConstant.TRACK_STAT_PLAY.equals(mqVo.getStatType())) {
            LambdaUpdateWrapper<AlbumStat> albumStatLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            albumStatLambdaUpdateWrapper.eq(AlbumStat::getAlbumId, mqVo.getAlbumId());
            albumStatLambdaUpdateWrapper.eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_PLAY);
            albumStatLambdaUpdateWrapper.setSql("stat_num = stat_num+" + mqVo.getCount());
            albumStatMapper.update(null, albumStatLambdaUpdateWrapper);
        }
        //3.如果统计类型是：声音评论 所属专辑统计信息也一并修改
        if (SystemConstant.TRACK_STAT_COMMENT.equals(mqVo.getStatType())) {
            LambdaUpdateWrapper<AlbumStat> albumStatLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            albumStatLambdaUpdateWrapper.eq(AlbumStat::getAlbumId, mqVo.getAlbumId());
            albumStatLambdaUpdateWrapper.eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_COMMENT);
            albumStatLambdaUpdateWrapper.setSql("stat_num = stat_num+" + mqVo.getCount());
            albumStatMapper.update(null, albumStatLambdaUpdateWrapper);
        }
    }

    /**
     * 查询声音统计信息
     * @param trackId
     * @return
     */
    @Override
    public TrackStatVo getTrackStatVo(Long trackId) {
        return trackInfoMapper.getTrackStatVo(trackId);
    }


}
